package com.hirstlogics.boxarrow.command;

import java.util.List;

import com.hirstlogics.boxarrow.box.ArrowSort;
import com.hirstlogics.boxarrow.box.Box;
import com.hirstlogics.boxarrow.model.Description;
import com.hirstlogics.boxarrow.model.Model;

public abstract class Command {
	
	abstract public Continuation perform(Continuation cont, String arg);
	
	static boolean hasModel(Continuation continuation) {
		boolean nullModel = continuation.getModel()==null;
		if (nullModel) System.out.println("You must create or open a model.");
		return !nullModel;
	}
	
	static boolean hasBoxArg(Continuation continuation) {
		boolean noArgs = !hasModel(continuation) || (continuation.boxStack.size() == 0);
		if (noArgs) System.out.println("First make a new Box");
		return !noArgs;
	}
	
	static Command createCommand(int code) {
		Command cmd=null; 
			
			switch (code) {
			case LineParser.NEWMODEL_CODE:
			{
				cmd = new Command() {
					@Override
					public Continuation perform(Continuation continuation, String arg) {
						continuation.clear();
						Model newModel = new Model(arg);
						newModel.addBox(new ArrowSort("isA-arrow",true,false,false));
						continuation.setModel(newModel);
						return continuation;
					}};
					break;
			}
			
			case LineParser.SETDESC_CODE: {
				cmd = new Command() {
					@Override
					public Continuation perform(Continuation continuation, String arg) {
						if (hasModel(continuation)) {
							continuation.getModel().setDescription(new Description(arg));
						}
						return continuation;
					}};
					break;
				
			}
				
			case LineParser.INFO_CODE :
			{
				cmd = new Command() {
					@Override
					public Continuation perform(Continuation continuation, String arg) {
						continuation.displayInfo();
						return continuation;
					}};
					break;
			}
			
			case LineParser.LISTBOXES_CODE: {
				cmd = new Command() {
					@Override
					public Continuation perform(Continuation continuation, String arg) {
						if (arg.isEmpty()) continuation.getModel().displayBoxes();
						else {
							// TODO: find container and display it's boxes
						}
						return continuation;
					}};
					break;
			
			}
			
			case LineParser.NEWBOX_CODE:
				cmd = new Command() {
					@Override
					public Continuation perform(Continuation continuation, String arg) {
						int breakAt = arg.indexOf(" ");
						if (breakAt==-1) System.out.println("try: newBox <type> <args>");
						else if (hasModel(continuation)) { 
							String boxType = arg.substring(0, breakAt);
							System.out.println("making a box of type: "+boxType);
							Box newBox = Box.createInstance(boxType,arg.substring(breakAt+1));
							continuation.pushBox(newBox);
						}
						return continuation;
					}};
					break;
					
			case LineParser.ADDBOX_CODE: {
				 cmd = new Command() {
						@Override
						public Continuation perform(Continuation continuation, String arg) {
							if (hasBoxArg(continuation)) continuation.getModel().addBox(continuation.popBox());
							return continuation;
						}};
				break;
			}
			
			case LineParser.SAVEAS_CODE: {
				cmd = new Command() {
					@Override
					public Continuation perform(Continuation continuation, String arg) {
						System.out.println("Saving model to:"+arg);
						if (hasModel(continuation)) continuation.getModel().saveAs(arg);
						return continuation;
					}};
					break;
				
			}
			
			case LineParser.SAVE_CODE: {
				cmd = new Command() {
					@Override
					public Continuation perform(Continuation continuation, String arg) {
						if (hasModel(continuation)) {
							if (continuation.getModel().isPersisted()) continuation.getModel().save();
							else System.out.println("Not yet saved as file.");
						}
						return continuation;
					}};
					break;
			}
			
			case LineParser.OPEN_CODE: {
				cmd = new Command() {
					@Override
					public Continuation perform(Continuation continuation, String arg) {
						System.out.println("Opening model from:"+arg);
						if (!arg.isEmpty()) continuation.setModel(Model.open(arg));
						return continuation;
					}};
					break;

			}

			case LineParser.HELP_CODE: {
				cmd = new Command() {
					@Override
					public Continuation perform(Continuation continuation, String arg) {
						System.out.println("Commands: ");
						for (int idx=0;idx<LineParser.commands.length;idx++) {
							System.out.println("   "+LineParser.commands[idx]);						
						}
						return continuation;
					}};
					break;

			}

			case LineParser.FIND_CODE: {
				cmd = new Command() {
					@Override
					public Continuation perform(Continuation continuation, String arg) {
						if (hasModel(continuation)) {
							System.out.println("Looking for Boxes named: '"+arg+"'");
							List<Box> boxes = continuation.model.findBoxesBy(arg);
							System.out.println("Found "+boxes.size());
							for (int idx=0;idx<boxes.size();idx++) {
								continuation.boxStack.add(boxes.get(idx));
							}
						}
						return continuation;
					}};
					break;
			}
			
			case LineParser.POPSTACK_CODE: {
				cmd = new Command() {
					@Override
					public Continuation perform(Continuation continuation, String arg) {
						if (hasModel(continuation)) {
							continuation.popBox();
						}
						return continuation;
					}};
					break;
			}
			
			case LineParser.QUIT_CODE: {
				cmd = new Command() {
					@Override
					public Continuation perform(Continuation continuation, String arg) {
						return continuation;
					}};
					break;
			}
			
			default: cmd = new Command() {
				@Override
				public Continuation perform(Continuation continuation, String arg) {
					System.out.println("No Match, try 'help' for list.");
					return continuation;
				}};
			}
			return cmd;
	}

}
